from sqlalchemy.ext.declarative import declarative_base, AbstractConcreteBase
from sqlalchemy import Column, Integer, DateTime
import decimal

from environment import environment, engine
from core.utils.time_utils import DateTimeUtils

class_registry = {}  # 为了拿到创建表的所有的类
Base = declarative_base(engine, class_registry=class_registry)

# 解决错误does not have a __table__ or __tablename__ specified and does not inherit from an existing table-mapped class.
# 添加 AbstractConcreteBase 继承或者在类中添加__abstract__ = True 表明当前类只用于继承


class BaseModel(AbstractConcreteBase, Base):
    id = Column(Integer, primary_key=True, autoincrement=True)
    create_time = Column(DateTime, doc='创建时间')
    operate_time = Column(DateTime, doc='修改时间')

    @classmethod
    def db(cls):
        return environment.db

    @classmethod
    def create_data(cls, info):
        if "id" in info:
            del info["id"]

        info["create_time"] = DateTimeUtils.get_current_datetime_str()
        info["operate_time"] = DateTimeUtils.get_current_datetime_str()

        info = cls.parse_table_info(cls, info)

        obj = cls.get_storage_object()

        _obj = obj(**info)

        cls.db().add(_obj)
        cls.db().flush()
        cls.db().commit()
        return _obj.super_get_json(_obj.id)

    @classmethod
    def update_data(cls, id_, info):
        # 得到查询对象
        obj = cls.db().query(cls).filter(cls.id == id_).first()
        info["operate_time"] = DateTimeUtils.get_current_datetime_str()
        info = cls.parse_table_info(cls, info)
        # 遍历修改
        [setattr(obj, _k, _v) for _k, _v in info.items()]
        cls.db().commit()
        return info

    @classmethod
    def remove_data(cls, id_):
        cls.db().query(cls.id).filter(cls.id == id_).delete()
        cls.db().commit()
        return True

        # 批量增加
    @classmethod
    def batch_add(cls, info_list):
        # 过滤表格没有的属性
        info_list = [
            cls.parse_table_info(cls, insert_obj) for insert_obj in info_list
        ]

        cls_list = [cls(**_i) for _i in info_list]
        cls.db().add_all(cls_list)
        cls.db().commit()

    # 批量删除
    @classmethod
    def batch_remove(cls, ids):
        if len(ids) == 0:
            return True

    @classmethod
    def get_storage_object(cls):
        """
        当前方法用于改变查询的模型
        """
        return cls

    def get_origin_object(self):
        return self

    @classmethod
    def super_get_json(cls, id_, is_stand=False):
        _table = cls.get_storage_object()
        _res = cls.db().query(_table).filter(_table.id == id_).first()
        if not _res:
            return {}
        cls.db().refresh(_res)
        result = {id_: _res.json}
        if not is_stand:
            fields = cls.get_origin_fields()
            if fields:
                cls.dict_info_parse(fields, result)

        return result.get(id_)

    @classmethod
    def super_mget_json(cls, ids, is_stand=False, id_map=True):
        # 限制获取长度

        _table = cls.get_storage_object()
        _res = cls.db().query(_table).filter(_table.id.in_(ids)).all()
        _ret = {cls.id_format(_r.id): _r.json for _r in _res}
        if not is_stand:
            # 获取关联字段
            fields = cls.get_origin_fields()
            if fields and _ret:
                # 添加关联字段
                cls.dict_info_parse(fields, _ret)
        if not id_map:
            _ret = [_i for _i in _ret.values()]
        return _ret

    @classmethod
    def dict_info_parse(cls, fields, result):
        """根据数据库配置，增加返回结果信息,注意判断result是否有值，他是网result中添加额外的信息
        :param fields: _description_
        :param result: {id:id_info}
        """
        # fields是一个列表
        for _f in fields:
            _name = _f.get("name")
            _object = _f.get("object")
            _model = DataModelFactory.get_model(_object)
            _result_ids = [_key for _key in result.keys()]
            # 获取到模型关联字段的ids
            _object_ids = [_value.get(_name) for _value in result.values()]
            if(len(_result_ids) == 1):
                _result_id = _result_ids[0]
                _object_id = _object_ids[0]
                # 默认获取到第二层
                _object = _model.super_get_json(_object_id, is_stand=True)
                result[_result_id][_name[:-3]] = _object
            else:
                # 获取到这个模型上所有的id
                _objects = _model.super_mget_json(_object_ids, is_stand=True)
                # 遍历result添加关联
                for _i in result.values():
                    _object_id = _i.get(_name)
                    result

                for _result_id, _result in result.items():
                    _object_id = _result.get(_name)
                    _object = _objects.get(_object_id)
                    result[_result_id][_name[:-3]] = _object

    def to_json(self):
        def get_value(_field):
            # 进行数据类型的转化,特别是一些时间的转化
            _value = getattr(obj, _field.name)
            if _field.type.__visit_name__ == 'datetime':
                _value = self.get_datetime_field_string(_value)
            elif _field.type.__visit_name__ == 'date':
                _value = self.get_date_field_string(_value)
            elif isinstance(_value, decimal.Decimal):
                _value = float(_value)
            elif _field.type.__visit_name__ == "time":
                _value = self.get_time_field_string(_value)

            return _value

        obj = self.get_origin_object()
        info = {_c.name: get_value(_c) for _c in obj.__table__.columns}

        return info

    @classmethod
    def get_datetime_field_string(cls, field):
        return None if field is None else field if isinstance(field, str) else field.strftime('%Y-%m-%d %H:%M:%S')

    @classmethod
    def get_date_field_string(cls, field):
        return None if field is None else field if isinstance(field, str) else field.strftime('%Y-%m-%d')

    @staticmethod
    def get_time_field_string(field):
        return None if field is None else field if isinstance(field, str) else field.strftime('%H:%M:%S')

    @property
    def json(self):
        return self.to_json()

    # 批量修改

    @staticmethod
    def parse_table_info(table, info):
        """
        处理新增的字段为表格中的字段
        """
        res = {}
        table_props = [
            _i.name for _i in table.__table__.columns if _i.name != "id"]

        for _k, _v in info.items():
            if _k in table_props:
                res[_k] = _v
            else:
                continue
        return res

    @classmethod
    def get_origin_fields(cls):
        """
        获取模型中相关的字段定义,如下
            create_time = Column(DateTime, doc='创建时间')，进行映射
            core/ds/base.py
        """
        # 获取到原模型
        _table = cls.__table__
        _columns = _table.columns

        return [
            dict(name=_c.name, object=_c.info.get("object")) for _c in _columns if getattr(_c, "info", {}).get("object")
        ]

    @staticmethod
    def id_format(id_):
        return id_


class ModelFactory:

    @classmethod
    def info_object_parse(cls, info, info_dict):
        """
        传递info获取其关联字段的值

        :param info: 单个表的数据
        :param info_dict: 表关联的相关信息
        """
        pass


class DataModelFactory:
    __factory_name__ = "标准模型"

    @classmethod
    def get_model(cls, name, default='None'):
        _model = class_registry.get(name)
        if default == 'None' and _model is None:
            return 'Unknown Model Name:{}'.format(name)
        return _model or default
